/**
 * All rights Reserved
 *
 * @Title: GoodsServiceImpl.java
 * @Package com.amigo.online.provider.merchant.service.impl
 * @Description: (用一句话描述该文件做什么)
 * @author: zxy  QQ:1363320658
 * @date: 2018年12月17日 下午4:30:07
 * @version V1.0
 * @Copyright: 2018  All rights reserved.
 */
package com.amigo.online.provider.merchant.service.impl;

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.amigo.online.common.param.result.UserInfo;
import com.amigo.online.common.param.result.goods.GoodsDetailInfo;
import com.amigo.online.common.param.result.goods.GoodsImgInfo;
import com.amigo.online.common.param.result.goods.HomeGoodsInfo;
import com.amigo.online.common.param.result.merchant.GoodsCommentInfo;
import com.amigo.online.common.param.result.merchant.MerchantCacheInfo;
import com.amigo.online.common.util.TimeUtil;
import com.amigo.online.provider.merchant.aspect.CommonCheck;
import com.amigo.online.provider.merchant.common.ConstantValue;
import com.amigo.online.provider.merchant.common.GlobalController;
import com.amigo.online.provider.merchant.common.MerchantRedisKey;
import com.amigo.online.provider.merchant.common.RwRedisService;
import com.amigo.online.provider.merchant.mapper.GoodsCollectMapper;
import com.amigo.online.provider.merchant.mapper.GoodsImgMapper;
//192.168.10.223:3000/wangbibang/amigo-online.git
import com.amigo.online.provider.merchant.mapper.GoodsMapper;
import com.amigo.online.provider.merchant.mapper.MerchantManagerMapper;
import com.amigo.online.provider.merchant.mapper.MerchantMapper;
import com.amigo.online.provider.merchant.model.entity.Goods;
import com.amigo.online.provider.merchant.model.entity.GoodsImg;
//192.168.10.223:3000/wangbibang/amigo-online.git
import com.amigo.online.provider.merchant.mongo.dao.GoodsDao;
import com.amigo.online.provider.merchant.service.GoodsCommentService;
import com.amigo.online.provider.merchant.service.GoodsImgService;
import com.amigo.online.provider.merchant.service.GoodsService;
import com.amigo.online.provider.merchant.service.UserFeignService;
import com.amigo.online.provider.merchant.utils.LocationUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCursor;

/**
 * @version: V 1.0.0
 * @Description: （商品接口实现类）
 * @author: zxy QQ:1363320658
 * @date: 2018年12月17日 下午4:30:07
 *
 */

@Service
public class GoodsServiceImpl implements GoodsService {

    private static final Logger logger = LoggerFactory.getLogger(GoodsServiceImpl.class);

    @Autowired
    private RwRedisService redisService;

    @Autowired
    GoodsMapper goodsMapper;

    @Autowired
    GoodsDao goodsDao;

    @Autowired
    MerchantManagerMapper merchantManagerMapper;

    @Autowired
    MerchantMapper merchantMapper;

    @Autowired
    GoodsImgService goodsImgService;

    @Autowired
    GoodsImgMapper goodsImgMapper;

    @Autowired
    GoodsCommentService goodsCommentService;

    @Autowired
    UserFeignService userFeignService;

    @Autowired
    GoodsCollectMapper goodsCollectMapper;

    /**
     * <p>
     * Title: findHotGoods
     * </p>
     * <p>
     * Description:
     * </p>
     *
     * @param label
     * @param category
     * @param service
     * @param minPrice
     * @param maxPrice
     * @return
     * @see com.amigo.online.provider.merchant.service.GoodsService#findHotGoods(java.lang.Integer,
     *      java.lang.Integer, java.lang.Integer, java.lang.Integer,
     *      java.lang.Integer)
     */
    @Override
    public List<HomeGoodsInfo> findHotGoods(Integer page, Integer label, Integer category, Integer service,
                                            Integer minPrice, Integer maxPrice) {
        if (label == null || label <= ConstantValue.GOODS_CATEGORY_ALL) {
            category = null;
            label = null;
        }
        if (null == page || page <= 0) {
            page = 1;
        }
        int start = (page - 1) * ConstantValue.HOME_SEARCH_SHOW_SIZE;
        List<HomeGoodsInfo> result = goodsMapper.findHotGoods(label, category, service, minPrice, maxPrice, start,
                ConstantValue.HOME_SEARCH_SHOW_SIZE);
        return result;
    }

    /**
     * <p>
     * Title: findRecommendGoods
     * </p>
     * <p>
     * Description:
     * </p>
     *
     * @param label
     * @param category
     * @param service
     * @param minPrice
     * @param maxPrice
     * @return
     * @see com.amigo.online.provider.merchant.service.GoodsService#findRecommendGoods(java.lang.Integer,
     *      java.lang.Integer, java.lang.Integer, java.lang.Integer,
     *      java.lang.Integer)
     */
    @Override
    public List<HomeGoodsInfo> findRecommendGoods(Integer page, Integer label, Integer category, Integer service,
                                                  Integer minPrice, Integer maxPrice) {
        if (label == null || label <= ConstantValue.GOODS_CATEGORY_ALL) {
            category = null;
            label = null;
        }
        if (null == page || page <= 0) {
            page = 1;
        }
        int start = (page - 1) * ConstantValue.HOME_SEARCH_SHOW_SIZE;
        List<HomeGoodsInfo> result = goodsMapper.findRecommendGoods(label, category, service, minPrice, maxPrice, start,
                ConstantValue.HOME_SEARCH_SHOW_SIZE);
        return result;
    }

    /**
     * <p>
     * Title: findNearestGoods
     * </p>
     * <p>
     * Description:
     * </p>
     *
     * @param label
     * @param category
     * @param service
     * @param minPrice
     * @param maxPrice
     * @param longitude
     * @param latitude
     * @return
     * @see com.amigo.online.provider.merchant.service.GoodsService#findNearestGoods(java.lang.Integer,
     *      java.lang.Integer, java.lang.Integer, java.lang.Integer,
     *      java.lang.Integer, java.lang.Double, java.lang.Double)
     */
    @Override
    public List<HomeGoodsInfo> findNearestGoods(Integer page, Integer label, Integer category, Integer service,
                                                Integer minPrice, Integer maxPrice, Double longitude, Double latitude) {
        BasicDBObject obQuery = new BasicDBObject();
        if (label != null && label > ConstantValue.GOODS_CATEGORY_ALL) {
            obQuery.append("label_id", label);
            if (category != null) {
                obQuery.append("category_id", category);
            }
        }
        if (service != null) {
            if (service == 1) {
                obQuery.append("discount_price", new BasicDBObject("$ne", null));
            }
        }

        if (minPrice != null) {
            obQuery.append("discount_price", new BasicDBObject("$gte", minPrice * ConstantValue.MONEY_CONVERSION_COEFFICIENT));
        }
        if (maxPrice != null) {
            obQuery.append("discount_price", new BasicDBObject("$lte", maxPrice * ConstantValue.MONEY_CONVERSION_COEFFICIENT));
        }
        obQuery.put("status", ConstantValue.GOODS_NORMAL_STATUS_CODE);
        obQuery.put("deleted", ConstantValue.DATA_NOT_DELETED);
        List<BasicDBObject> pipeline = new ArrayList<>();
        if (null == page || page <= 0) {
            page = 1;
        }
        Double[] point = new Double[]{longitude, latitude};
        BasicDBObject skipObject = new BasicDBObject("$skip", (page - 1) * ConstantValue.HOME_SEARCH_SHOW_SIZE);
        pipeline.add(skipObject);
        BasicDBObject limitObject = new BasicDBObject("$limit", ConstantValue.HOME_SEARCH_SHOW_SIZE);
        pipeline.add(limitObject);
        List<HomeGoodsInfo> result = new ArrayList<>();
        AggregateIterable<Document> iterators = goodsDao.findAroundGoods(ConstantValue.MONGO_GOODS, point,
                ConstantValue.HOME_SEARCH_SHOW_DISTANCE, obQuery, pipeline);
        MongoCursor<Document> cursor = iterators.iterator();
        while (cursor.hasNext()) {
            Document doc = cursor.next();
            HomeGoodsInfo tempObj = new HomeGoodsInfo();
            tempObj.setId(doc.getLong("_id"));
            tempObj.setCoverImg(doc.getString("cover_img"));
            tempObj.setFeedback(doc.getInteger("feedback"));
            tempObj.setTitle(doc.getString("title"));
            tempObj.setPrice(doc.getInteger("price"));
            tempObj.setDiscountPrice(doc.getInteger("discount_price"));
            tempObj.setMerchantId(doc.getLong("merchant_id"));
            tempObj.setMerchantName(doc.getString("merchant_name"));
            result.add(tempObj);
        }
        return result;
    }

    @Override
    public JSONObject getGoodsDetailById(Long goodsId, String lat, String lng) {
        GoodsDetailInfo goodsInfo = goodsMapper.getGoodsDetailById(goodsId);
        if (goodsInfo == null)
            goodsInfo = new GoodsDetailInfo();
        setDistance(lat, lng, goodsInfo);
        // 查出商品的图片
        setImgs(goodsId, goodsInfo);
        // 判断是否在营业中
        setOpened(goodsInfo);
        // 判断用户是否收藏了该店铺
        setCollected(goodsInfo);
        // 获取商品评论
        GoodsCommentInfo comment = goodsCommentService.getCommentGoodsList(goodsId == null ? 0 : goodsId.intValue(), 0, 0,
                1, 2);
        JSONObject res = new JSONObject();
        res.put("goodsDetail", goodsInfo);
        res.put("comment", comment);
        // 获取商品所在店铺的店长的基本信息
        res.put("user", getStoreKeeperInfo(goodsId));
        return res;
    }

    private void setCollected(GoodsDetailInfo goodsInfo) {
        if (goodsInfo.getId() != null) {
            // int count =
            // goodsCollectMapper.getCountByUserIdAndGoodsId(GlobalController.getNowUser().getId(),
            // goodsInfo.getId());
            Long goodsCollectId = goodsCollectMapper
                    .getGoodsCollectIdByUserIdAndGoodsId(GlobalController.getNowUser().getId(), goodsInfo.getId());
            goodsInfo.setCollectId(goodsCollectId);
            goodsInfo.setCollected(goodsCollectId != null);
        }

    }

    private void setOpened(GoodsDetailInfo goodsInfo) {
        String startTime = goodsInfo.getStartTime();
        String endTime = goodsInfo.getEndTime();
        Integer startWeek = goodsInfo.getStartWeek();
        Integer endWeek = goodsInfo.getEndWeek();
        try {
            LocalDateTime nowTime = LocalDateTime.now();
            DayOfWeek nowWeek = nowTime.getDayOfWeek();
            // 生成一个开始星期几 -- 结束星期几的数组
            List<Integer> openWeekArray = TimeUtil.getOpenWeekArray(startWeek, endWeek);
            if (openWeekArray.contains(nowWeek.getValue())) {
                if (StringUtils.contains(startTime, ":") && StringUtils.contains(endTime, ":")) {
                    Integer st = Integer.valueOf(startTime.split(":")[0]);
                    Integer ed = Integer.valueOf(endTime.split(":")[0]);
                    if (nowTime.getHour() >= st && nowTime.getHour() <= ed) {
                        goodsInfo.setOpened(true);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("startTime:{},endTime{}", startWeek, endTime);
//			e.printStackTrace();

        }
    }

    private void setImgs(Long goodsId, GoodsDetailInfo goodsInfo) {
        List<GoodsImg> goodsImgs = goodsImgMapper.getImg(goodsId);
        for (GoodsImg goodsImg : goodsImgs) {
            if (goodsInfo.getShowImgs() != null && goodsImg.getType() == 1) { // 图片类型，1展示图片 2详情配图
                GoodsImgInfo goodsImgInfo = new GoodsImgInfo(goodsImg.getImgUrl(), goodsImg.getVideoUrl());
                goodsInfo.getShowImgs().add(goodsImgInfo);
            } else if (goodsInfo.getShowImgs() != null && goodsImg.getType() == 2) {
                GoodsImgInfo goodsImgInfo = new GoodsImgInfo(goodsImg.getImgUrl(), goodsImg.getVideoUrl());
                goodsInfo.getDetailImgs().add(goodsImgInfo);
            }
        }
    }

    private void setDistance(String lat, String lng, GoodsDetailInfo goodsInfo) {
        String distance = "";
        try {
            double dis = LocationUtils.getDistance(Double.valueOf(lat), Double.valueOf(lng),
                    Double.valueOf(goodsInfo.getLat()), Double.valueOf(goodsInfo.getLng()));
            distance = dis / 1000 < 0.1 ? "0.1km" : String.format("%.1f", dis / 1000) + "km";
        } catch (Exception e) {
            // 不用处理
        }
        goodsInfo.setDistance(distance);
    }

    private JSONObject getStoreKeeperInfo(Long goodsId) {
        Long userId = merchantMapper.getUserIdByGoodsId(goodsId);
        if (userId == null) {
            return new JSONObject();
        }
        Object response = userFeignService.getUserInfo(userId).getBody().getData();
        ObjectMapper mapper = new ObjectMapper();
        UserInfo userInfo = mapper.convertValue(response, UserInfo.class);
        JSONObject user = new JSONObject();
        if (userInfo != null) {
            user.put("id", userInfo.getId());
            user.put("avatar", userInfo.getAvatar());
            user.put("avatarSamll", userInfo.getAvatarSmall());
            user.put("nickname", userInfo.getNickname());
        }
        return user;
    }

    @Override
    public List<HomeGoodsInfo> getGoodsOrderBYField(Long merchantId, Integer page, Integer size, Integer type,
                                                    Long categoryId) {
        page = GlobalController.checkPage(page, size);
        Integer start = (page - 1) * size;
        return goodsMapper.getGoodsOrderBYField(merchantId, start, size, type, categoryId);
    }

    // 0-审核失败 1-审核中 2-上架中 3-下架中

    /**
     * <p>
     * Title: shelfMerchantGoodsByGoodsId
     * </p>
     * <p>
     * Description:
     * </p>
     *
     * @param id
     * @see com.amigo.online.provider.merchant.service.GoodsService#shelfMerchantGoodsByGoodsId(long)
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CommonCheck(methods = {"checkUserIsManager", "checkGoodsIsMerchantGoods"}, parameters = {"1,2", "2,3"})
    public void shelfMerchantGoodsByGoodsId(long userId, long merchantId, long goodsId) {
        /*
         * UserInfo userInfo = GlobalController.getNowUser();
         * commonMerchantGoodsCheck(goodsId, merchantId, userInfo.getId());
         */
        int result = goodsMapper.shelfMerchantGoodsByGoodsId(goodsId);
        if (result == 0) {
            logger.error("商户ID:{},商品ID:{},操作出现多操作更改覆盖的问题!修改状态为,操作人ID:{}!", merchantId, goodsId, userId);
        }
        @SuppressWarnings("unchecked")
        Long redisResult = redisService.opsForSet().add(MerchantRedisKey.MERCHANT_GOODS_SET, goodsId);
        if (redisResult == 0) {
            logger.error("上架商家商品缓存数据有误，操作员ID:{},商家ID:{},商品ID:{}", userId, merchantId, userId);
        }
    }

    /*
     * public void commonMerchantGoodsCheck(long goodsId, long merchantId, long
     * userId) { checkUserIsManager(userId, merchantId);
     * checkGoodsIsMerchantGoods(merchantId, goodsId); }
     */

    /**
     *
     * <p>
     * Title: deleteMerchantGoodsByGoodsId
     * </p>
     * <p>
     * Description:
     * </p>
     *
     * @param id
     * @param merchantId
     * @see com.amigo.online.provider.merchant.service.GoodsService#deleteMerchantGoodsByGoodsId(long,
     *      long)
     */
    @Override
    @Transactional()
    @CommonCheck(methods = {"checkUserIsManager", "checkGoodsIsMerchantGoods"}, parameters = {"1,2", "2,3"})
    public void deleteMerchantGoodsByGoodsId(long userId, long merchantId, long goodsId) {
        /*
         * UserInfo userInfo = GlobalController.getNowUser();
         * commonMerchantGoodsCheck(goodsId, merchantId, userInfo.getId());
         */
        int result = goodsMapper.deleteMerchantGoodsByGoodsId(goodsId);
        if (result == 0) {
            logger.error("商户ID:{},商品ID:{},删除操作出现多操作更改覆盖的问题!,操作人ID:{}!", merchantId, goodsId, userId);
        }
        @SuppressWarnings("unchecked")
        Long redisResult = redisService.opsForSet().remove(MerchantRedisKey.MERCHANT_GOODS_SET, goodsId);
        if (redisResult == 0) {
            logger.error("删除商家商品缓存数据有误，操作员ID:{},商家ID:{},商品ID:{}", userId, merchantId, userId);
        }
    }

    /**
     * <p>
     * Title: obtainedMerchantGoodsByGoodsId
     * </p>
     * <p>
     * Description:
     * </p>
     *
     * @param id
     * @see com.amigo.online.provider.merchant.service.GoodsService#obtainedMerchantGoodsByGoodsId(long)
     */
    @Override
    @Transactional()
    @CommonCheck(methods = {"checkUserIsManager", "checkGoodsIsMerchantGoods"}, parameters = {"1,2", "2,3"})
    public void obtainedMerchantGoodsByGoodsId(long userId, long merchantId, long goodsId) {
        /*
         * UserInfo userInfo = GlobalController.getNowUser();
         * commonMerchantGoodsCheck(goodsId, merchantId, userInfo.getId());
         */
        int result = goodsMapper.obtainedMerchantGoodsByGoodsId(goodsId);
        if (result == 0) {
            logger.error("商户ID:{},商品ID:{},上架操作出现多操作更改覆盖的问题!,操作人ID:{}!", merchantId, goodsId, userId);
        }
        @SuppressWarnings("unchecked")
        Long redisResult = redisService.opsForSet().remove(MerchantRedisKey.MERCHANT_GOODS_SET, goodsId);
        if (redisResult == 0) {
            logger.error("下架商家商品缓存数据有误，操作员ID:{},商家ID:{},商品ID:{}", userId, merchantId, userId);
        }
    }

    @Override
    @Transactional()
    @CommonCheck(methods = {"checkMerchantIfExist", "checkUserIsManager"}, parameters = {"2", "1,2"})
    public void newMerchantGoods(long userId, long merchantId, List<String> goodsImgList, List<String> goodsVideoList,
                                 String goodsName, Integer price, Integer discountPrice, Long category, List<String> goodsDetailImgList,
                                 Integer isAutoShelf) {
        // MerchantCacheInfo merchantCacheInfo = checkMerchantIfExist(merchantId);
        MerchantCacheInfo merchantCacheInfo = (MerchantCacheInfo) redisService
                .get(MerchantRedisKey.MERCHANT_CACHE_INFO + merchantId);
        Goods goods = new Goods(merchantCacheInfo.getId(), merchantCacheInfo.getMerchantName(), category, goodsName,
                price, discountPrice, ConstantValue.GOODS_STATUS_APPROVAL, merchantCacheInfo.getLat(),
                merchantCacheInfo.getLng(), isAutoShelf, merchantCacheInfo.getCategoryId());
        goods.setCoverImg(goodsImgList.get(0));
        goods.setFeedback(0);//默认0
        int result = goodsMapper.insertSelective(goods);
        if (result == 1) {
            goodsImgService.saveGoodsImgList(goods.getId(), goodsImgList, goodsVideoList, goodsDetailImgList);
        }

    }

    @Override
    @Transactional()
    @CommonCheck(methods = {"checkMerchantIfExist", "checkUserIsManager", "checkGoodsIsMerchantGoods"}, parameters = {
            "2", "1,2", "2,3"})
    public void editMerchantGoods(long userId, long merchantId, long goodsId, List<String> goodsImgList,
                                  List<String> goodsVideoList, String goodsName, Integer price, Integer discountPrice, Long category,
                                  List<String> goodsDetailImgList, Integer isAutoShelf) {
        MerchantCacheInfo merchantCacheInfo = (MerchantCacheInfo) redisService
                .get(MerchantRedisKey.MERCHANT_CACHE_INFO + merchantId);
        Goods goods = new Goods(merchantCacheInfo.getId(), merchantCacheInfo.getMerchantName(), category, goodsName,
                price, discountPrice, ConstantValue.GOODS_STATUS_APPROVAL, isAutoShelf, merchantCacheInfo.getCategoryId());
        goods.setId(goodsId);
        int result = goodsMapper.updateByPrimaryKeySelective(goods);
        if (result == 1) {
            goodsImgService.saveGoodsImgList(goods.getId(), goodsImgList, goodsVideoList, goodsDetailImgList);
        }
    }

    @Override
    @Transactional
    public void multiUpdateGoods(Map<Long, Double> weightMap) {
        goodsMapper.multiUpdateGoods(weightMap);
    }

}
